﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Smartee.RichText.VisitorAndBuilder
{
    public class Builder : IBuilder
    {
        private Document _document;
        private Body _currentBody;
        private Container _currentContainer;
        private Paragraph _footnoteParentParagraph;

        public Document Document { get { return _document; } }

        #region IBuilder Members

        public void StartDocument()
        {
            _document = new Document();
            _currentContainer = null;
            _footnoteParentParagraph = null;
            _currentBody = _document;
        }

        public void StartFontTable()
        {
            _document.Fonts.Clear();
        }

        public int AddFont(string fontFamily, string fontName)
        {
            _document.Fonts.Add(new FontConfiguration(fontFamily, fontName));

            return _document.Fonts.Count - 1;
        }

        public void EndFontTable()
        {
        }

        public void StartColorTable()
        {
            _document.Colors.Clear();
        }

        public int AddColor(byte red, byte green, byte blue)
        {
            _document.Colors.Add(new ColorConfiguration() { Red = red, Green = green, Blue = blue });
            return _document.Colors.Count;
        }

        public void EndColorTable()
        {
        }

        public void StartHeader()
        {
            _currentBody = _document.Header;
        }

        public void EndHeader()
        {
            _currentBody = _document;
        }

        public void StartFooter()
        {
            _currentBody = _document.Footer;
        }

        public void EndFooter()
        {
            _currentBody = _document;
        }

        public void StartTable(TextDirection tableDirection, Measurement[] columnsWidth, Justification[] columnsJustification)
        {
            if (_currentContainer != null)
                throw new Exception();

            Container newItem = new Table(tableDirection, columnsWidth, columnsJustification);
            _currentBody.Add(newItem);
            _currentContainer = newItem;
        }

        public void StartRow()
        {
            if (!(_currentContainer is Table))
                throw new Exception();

            Row newRow = new Row(_currentContainer as Table);
            (_currentContainer as Table).Add(newRow);
            _currentContainer = newRow;
        }

        public void StartCell()
        {
            if (!(_currentContainer is Row))
                throw new Exception();

            Cell newCell = new Cell(_currentContainer as Row);
            (_currentContainer as Row).Add(newCell);
            _currentBody = newCell;
            _currentContainer = null;
        }

        public void EndCell()
        {
            _currentContainer = (_currentBody as Cell).ParentRow;
            _currentBody = _document;
        }

        public void EndRow()
        {
            _currentContainer = (_currentContainer as Row).ParentTable;
        }

        public void EndTable()
        {
            _currentContainer = null;
        }

        public void StartParagraph(Justification justification, TextDirection textDirection)
        {
            if (_currentContainer != null)
                throw new Exception();

            Container newItem = new Paragraph(justification, textDirection);
            _currentBody.Add(newItem);
            _currentContainer = newItem;
        }

        public void InsertText(string text)
        {
            if (!(_currentContainer is Paragraph))
                throw new Exception();

            Text textItem = new Text();
            textItem.Content = text;

            (_currentContainer as Paragraph).Add(textItem);
        }

        public void InsertNewLine()
        {
            if (!(_currentContainer is Paragraph))
                throw new Exception();

            NewLine newItem = new NewLine();

            (_currentContainer as Paragraph).Add(newItem);
        }

        public bool BoldFace
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new BoldFaceModifier(value));
            }
        }

        public bool Underline
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new UnderlineModifier(value));
            }
        }

        public bool Strike
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new StrikeModifier(value));
            }
        }

        public int FontId
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new FontModifier(value));
            }
        }

        public int ForegoundColorId
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new ForegoundColorModifier(value));
            }
        }

        public int BackgoundColorId
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new BackgoundColorModifier(value));
            }
        }

        public TextDirection CharacterDirection
        {
            set
            {
                if (!(_currentContainer is Paragraph))
                    throw new Exception();

                (_currentContainer as Paragraph).Add(new TextDirectionModifier(value));
            }
        }

        public void StartFootnote()
        {
            if (!(_currentContainer is Paragraph) || _currentBody != _document || _footnoteParentParagraph != null)
                throw new Exception();

            Footnote note = new Footnote();
            (_currentContainer as Paragraph).Add(note);

            _footnoteParentParagraph = _currentContainer as Paragraph;
            _currentBody = note.Note;
            _currentContainer = null;
        }

        public void StartFootnote(string identifier)
        {
            if (!(_currentContainer is Paragraph) || _currentBody != _document || _footnoteParentParagraph != null)
                throw new Exception();

            Footnote note = new Footnote(identifier);
            (_currentContainer as Paragraph).Add(note);

            _footnoteParentParagraph = _currentContainer as Paragraph;
            _currentBody = note.Note;
            _currentContainer = null;
        }

        public void EndFootnote()
        {
            _currentBody = _document;
            _currentContainer = _footnoteParentParagraph;
            _footnoteParentParagraph = null;
        }

        public void EndParagraph()
        {
            _currentContainer = null;
        }

        public void InsertPageBreak()
        {
            if (_currentContainer != null)
                throw new Exception();

            _currentBody.Add(new PageBreak());
        }

        public Document EndDocument()
        {
            return _document;
        }

        public void InsertPageNumber()
        {
            if (!(_currentContainer is Paragraph))
                throw new Exception();

            (_currentContainer as Paragraph).Add(new PageNumber());
        }

        #endregion
    }
}
